-- VS

uniform Matrices {
    mat4 Projection;
    mat4 Camera;
    mat3 NormalC;
} GlobalMatrices;

uniform Model {
    mat4 ModelView;
    mat3 NormalM;
} LocalModel;


in vec4 Position;
in vec3 Normal;
in vec2 TexCoords;

out vec3 vLocation;
out vec3 vNormal;
out vec2 vTexCoords;

void main()
{
    vec4 loc=GlobalMatrices.Camera*(LocalModel.ModelView*Position);
    vNormal=GlobalMatrices.NormalC*(LocalModel.NormalM*Normal);
    vLocation=loc.xyz;
    loc=GlobalMatrices.Projection*loc;
    vTexCoords=TexCoords;

    gl_Position=loc;
    // Some fun with Poincare disk
//    float scaleP = inversesqrt(dot(loc.xy,loc.xy));
//    loc.xy*=tanh(0.5/scaleP)*scaleP;
//    gl_Position=loc;
}

-- FS

struct Light {
    vec3 pos;
    vec4 color;    
};

uniform Lights {
    Light lights[MAX_LIGHTS];
} GlobalLights;

uniform sampler2D TexImg;

in vec3 vLocation;
in vec3 vNormal;
in vec2 vTexCoords;

out vec4 fColor;

#define INVERSE_4PI 0.07957747154594766788444188168626
const vec3 cEye=vec3(0,0,0);

vec3 Lighting(in vec3 normal, in vec3 location, in vec4 mat)
{
    vec3 outColor=vec3(0,0,0);
    vec3 view=normalize(cEye-location);
    for(int i=0; i<MAX_LIGHTS; i++)
        if(GlobalLights.lights[i].color.a > 0) {
            vec3 incoming=location-GlobalLights.lights[i].pos;
            float aten=inversesqrt(dot(incoming,incoming));
            incoming*=aten;
            aten*=aten*INVERSE_4PI*GlobalLights.lights[i].color.a;
            outColor-=min(0, dot(incoming, normal))*GlobalLights.lights[i].color.rgb*aten*mat.rgb;
            // Obtain <N,H>
            vec3 reflected=reflect(incoming, normal);
            float spec=(dot(reflected, view)+1)*0.5;
            float smoothness=1/(mat.a*mat.a);
            spec=1/spec;
            // compute the coefficient
            spec=exp((1-spec)*smoothness)*smoothness*spec*spec*INVERSE_4PI*4;
            // nullify in case of backface
            spec*=(sign(dot(reflected,normal))+1)*0.5;
            outColor+=spec*GlobalLights.lights[i].color.rgb*aten;
        }
    return outColor;
}

void main()
{
    vec3 normal=normalize(vNormal);
    vec4 outColor=vec4(0,0,0,1);
    outColor.rgb=Lighting(normal, vLocation, texture(TexImg, vTexCoords));
    
    //outColor.rgb=texture(TexImg, vTexCoords).rgb;
    fColor=outColor;
    //fColor=vec4(vTexCoords,0,1);
    //fColor=vec4(pow(outColor.rgb,vec3(1)),1);
    //fColor=vec4(vec3(pow(gl_FragCoord.x/1024,1)),1);
    //fColor=vec4(.8,.2,.2,1);
    //fColor=max(texture(TexImg, vTexCoords),fColor);
    //fColor=clamp(fColor,0,1);
}
